/**************************************************************************//**
* @file     2d.c
* @brief    N9H30 GE2D driver source file
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "rtthread.h"

#include "NuMicro.h"
#include <drv_sys.h>

//#define DEBUG
//#define DEF_COND_WAIT 1

static unsigned int GFX_BPP;
static unsigned int GFX_WIDTH;
static unsigned int GFX_HEIGHT;

#if defined ( __GNUC__ ) && !(__CC_ARM)
    __attribute__((aligned(32))) static void *GFX_START_ADDR = NULL;
    __attribute__((aligned(32))) static void *GFX_PAT_ADDR = NULL;
#else
    static __align(32) void *GFX_START_ADDR = NULL;
    static __align(32) void *GFX_PAT_ADDR = NULL;
#endif

#define  PN   1  // Quadrant 1
#define  NN   2  // Quadrant 2
#define  NP   3  // Quadrant 3
#define  PP   4  // Quadrant 4

#define ABS(x)      (((x)>0)?(x):-(x))
#define MAX(a,b)    (((a)>(b))?(a):(b))

/* octant code of line drawing */

#define XpYpXl      (0<<1)   // XY octant position is 1~3 in Control register
#define XpYpYl      (1<<1)
#define XpYmXl      (2<<1)
#define XpYmYl      (3<<1)
#define XmYpXl      (4<<1)
#define XmYpYl      (5<<1)
#define XmYmXl      (6<<1)
#define XmYmYl      (7<<1)

static MONOPATTERN MonoPatternData[6] =
{
    {0x00000000, 0xff000000}, // HS_HORIZONTAL
    {0x08080808, 0x08080808}, // HS_VERTICAL
    {0x80402010, 0x08040201}, // HS_FDIAGONAL
    {0x01020408, 0x10204080}, // HS_BDIAGONAL
    {0x08080808, 0xff080808}, // HS_CROSS
    {0x81422418, 0x18244281}  // HS_DIAGCROSS
};

static char _DrawMode = MODE_OPAQUE;
static UINT32 _ColorKey = COLOR_KEY;
static UINT32 _ColorKeyMask = 0xFFFFFF;

static BOOL _EnableAlpha = FALSE;
static int _AlphaKs, _AlphaKd;
static BOOL _ClipEnable = FALSE;
static BOOL _OutsideClip = FALSE;
static UINT32 _ClipTL, _ClipBR;
static int _PatternType;

static unsigned char FontData8[256][8] =
{
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //0
    {0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E}, //1
    {0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E}, //2
    {0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00}, //3
    {0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00}, //4
    {0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x92, 0x10, 0x7C}, //5
    {0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C}, //6
    {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, //7
    {0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF}, //8
    {0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00}, //9
    {0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF}, //10
    {0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78}, //11
    {0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18}, //12
    {0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0}, //13
    {0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0}, //14
    {0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99}, //15
    {0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00}, //16
    {0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00}, //17
    {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18}, //18
    {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, //19
    {0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00}, //20
    {0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0x86, 0xFC}, //21
    {0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00}, //22
    {0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF}, //23
    {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00}, //24
    {0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00}, //25
    {0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00}, //26
    {0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00}, //27
    {0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00}, //28
    {0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00}, //29
    {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00}, //30
    {0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00}, //31
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //32
    {0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, //33
    {0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00}, //34
    {0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00}, //35
    {0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00}, //36
    {0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00}, //37
    {0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00}, //38
    {0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, //39
    {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00}, //40
    {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00}, //41
    {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, //42
    {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, //43
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, //44
    {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //45
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, //46
    {0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00}, //47
    {0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00}, //48
    {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00}, //49
    {0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00}, //50
    {0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00}, //51
    {0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00}, //52
    {0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00}, //53
    {0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00}, //54
    {0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00}, //55
    {0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //56
    {0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00}, //57
    {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00}, //58
    {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30}, //59
    {0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00}, //60
    {0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, //61
    {0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00}, //62
    {0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00}, //63
    {0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00}, //64
    {0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00}, //65
    {0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00}, //66
    {0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00}, //67
    {0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00}, //68
    {0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00}, //69
    {0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00}, //70
    {0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00}, //71
    {0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00}, //72
    {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //73
    {0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00}, //74
    {0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00}, //75
    {0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00}, //76
    {0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00}, //77
    {0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00}, //78
    {0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00}, //79
    {0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00}, //80
    {0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00}, //81
    {0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00}, //82
    {0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00}, //83
    {0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //84
    {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00}, //85
    {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00}, //86
    {0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00}, //87
    {0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00}, //88
    {0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00}, //89
    {0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00}, //90
    {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00}, //91
    {0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00}, //92
    {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00}, //93
    {0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, //94
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, //95
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //96
    {0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //97
    {0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00}, //98
    {0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00}, //99
    {0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00}, //100
    {0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //101
    {0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00}, //102
    {0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //103
    {0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00}, //104
    {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //105
    {0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78}, //106
    {0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00}, //107
    {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //108
    {0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00}, //109
    {0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00}, //110
    {0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00}, //111
    {0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0}, //112
    {0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E}, //113
    {0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00}, //114
    {0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00}, //115
    {0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00}, //116
    {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //117
    {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00}, //118
    {0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00}, //119
    {0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00}, //120
    {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //121
    {0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00}, //122
    {0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00}, //123
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, //124
    {0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00}, //125
    {0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //126
    {0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00}, //127
    {0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x0C, 0x06, 0x7C}, //128
    {0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //129
    {0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //130
    {0x7E, 0x81, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0x00}, //131
    {0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //132
    {0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //133
    {0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //134
    {0x00, 0x00, 0x7C, 0xC6, 0xC0, 0x78, 0x0C, 0x38}, //135
    {0x7E, 0x81, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00}, //136
    {0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //137
    {0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //138
    {0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //139
    {0x7C, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00}, //140
    {0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //141
    {0xC6, 0x10, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00}, //142
    {0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00}, //143
    {0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00}, //144
    {0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00}, //145
    {0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00}, //146
    {0x78, 0x84, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //147
    {0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //148
    {0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //149
    {0x78, 0x84, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //150
    {0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //151
    {0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //152
    {0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, //153
    {0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00}, //154
    {0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18}, //155
    {0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00}, //156
    {0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0xFC, 0x30}, //157
    {0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC3}, //158
    {0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70}, //159
    {0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //160
    {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //161
    {0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //162
    {0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //163
    {0x00, 0xF8, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0x00}, //164
    {0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00}, //165
    {0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00}, //166
    {0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00}, //167
    {0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3C, 0x00}, //168
    {0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00}, //169
    {0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00}, //170
    {0xC6, 0xCC, 0xD8, 0x36, 0x6B, 0xC2, 0x84, 0x0F}, //171
    {0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6D, 0xCF, 0x03}, //172
    {0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x00}, //173
    {0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, //174
    {0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, //175
    {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88}, //176
    {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, //177
    {0xDB, 0xF6, 0xDB, 0x6F, 0xDB, 0x7E, 0xD7, 0xED}, //178
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //179
    {0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18}, //180
    {0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18}, //181
    {0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36}, //182
    {0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36}, //183
    {0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18}, //184
    {0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36}, //185
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //186
    {0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36}, //187
    {0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00}, //188
    {0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00}, //189
    {0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00}, //190
    {0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18}, //191
    {0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00}, //192
    {0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00}, //193
    {0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18}, //194
    {0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18}, //195
    {0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, //196
    {0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18}, //197
    {0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18}, //198
    {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36}, //199
    {0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00}, //200
    {0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36}, //201
    {0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00}, //202
    {0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36}, //203
    {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36}, //204
    {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, //205
    {0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36}, //206
    {0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, //207
    {0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00}, //208
    {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18}, //209
    {0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36}, //210
    {0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00}, //211
    {0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00}, //212
    {0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18}, //213
    {0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36}, //214
    {0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36}, //215
    {0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18}, //216
    {0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00}, //217
    {0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18}, //218
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //219
    {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, //220
    {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, //221
    {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, //222
    {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, //223
    {0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00}, //224
    {0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0}, //225
    {0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00}, //226
    {0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x00}, //227
    {0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00}, //228
    {0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00}, //229
    {0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0}, //230
    {0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00}, //231
    {0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC}, //232
    {0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00}, //233
    {0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00}, //234
    {0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00}, //235
    {0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00}, //236
    {0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0}, //237
    {0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00}, //238
    {0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00}, //239
    {0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00}, //240
    {0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00}, //241
    {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00}, //242
    {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00}, //243
    {0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18}, //244
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70}, //245
    {0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00}, //246
    {0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00}, //247
    {0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //248
    {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, //249
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00}, //250
    {0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C}, //251
    {0x58, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00}, //252
    {0x70, 0x98, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00}, //253
    {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, //254
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //255
};

static unsigned char FontData16[256][16] =
{
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //0
    {0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00}, //1
    {0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00}, //2
    {0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00}, //3
    {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, //4
    {0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //5
    {0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //6
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //7
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //8
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00}, //9
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //10
    {0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00}, //11
    {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //12
    {0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00}, //13
    {0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00}, //14
    {0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //15
    {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00}, //16
    {0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, //17
    {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //18
    {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //19
    {0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00}, //20
    {0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00}, //21
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00}, //22
    {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00}, //23
    {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //24
    {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //25
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //26
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //27
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //28
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //29
    {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //30
    {0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, //31
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //32
    {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //33
    {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //34
    {0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //35
    {0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00}, //36
    {0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00}, //37
    {0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //38
    {0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //39
    {0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00}, //40
    {0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00}, //41
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //42
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //43
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00}, //44
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //45
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //46
    {0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00}, //47
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //48
    {0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00}, //49
    {0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //50
    {0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //51
    {0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00}, //52
    {0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //53
    {0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //54
    {0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00}, //55
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //56
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00}, //57
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //58
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00}, //59
    {0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, //60
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //61
    {0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00}, //62
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //63
    {0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00}, //64
    {0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //65
    {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00}, //66
    {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00}, //67
    {0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00}, //68
    {0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //69
    {0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //70
    {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00}, //71
    {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //72
    {0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //73
    {0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00}, //74
    {0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //75
    {0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //76
    {0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //77
    {0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //78
    {0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //79
    {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //80
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00}, //81
    {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //82
    {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //83
    {0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //84
    {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //85
    {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00}, //86
    {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //87
    {0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //88
    {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //89
    {0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //90
    {0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00}, //91
    {0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, //92
    {0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00}, //93
    {0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //94
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00}, //95
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //96
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //97
    {0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x00}, //98
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //99
    {0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //100
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //101
    {0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //102
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00}, //103
    {0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //104
    {0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //105
    {0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00}, //106
    {0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //107
    {0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //108
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00}, //109
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //110
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //111
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00}, //112
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00}, //113
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //114
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //115
    {0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, //116
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //117
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //118
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00}, //119
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, //120
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00}, //121
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //122
    {0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00}, //123
    {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //124
    {0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00}, //125
    {0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //126
    {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //127
    {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00}, //128
    {0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //129
    {0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //130
    {0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //131
    {0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //132
    {0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //133
    {0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //134
    {0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00}, //135
    {0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //136
    {0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //137
    {0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //138
    {0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //139
    {0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //140
    {0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //141
    {0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //142
    {0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //143
    {0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //144
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00}, //145
    {0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00}, //146
    {0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //147
    {0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //148
    {0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //149
    {0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //150
    {0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //151
    {0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00}, //152
    {0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //153
    {0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //154
    {0x00, 0x18, 0x18, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //155
    {0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00}, //156
    {0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //157
    {0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00}, //158
    {0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0x70, 0x00, 0x00}, //159
    {0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //160
    {0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //161
    {0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //162
    {0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //163
    {0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //164
    {0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //165
    {0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //166
    {0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //167
    {0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //168
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, //169
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, //170
    {0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06, 0x0C, 0x1F, 0x00, 0x00}, //171
    {0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00, 0x00}, //172
    {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //173
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //174
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //175
    {0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44}, //176
    {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, //177
    {0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77}, //178
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //179
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //180
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //181
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //182
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //183
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //184
    {0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //185
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //186
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //187
    {0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //188
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //189
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //190
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //191
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //192
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //193
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //194
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //195
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //196
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //197
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //198
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //199
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //200
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //201
    {0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //202
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //203
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //204
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //205
    {0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //206
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //207
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //208
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //209
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //210
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //211
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //212
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //213
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //214
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //215
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //216
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //217
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //218
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //219
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //220
    {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, //221
    {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, //222
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //223
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00}, //224
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00, 0x00}, //225
    {0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00}, //226
    {0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //227
    {0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //228
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00}, //229
    {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00}, //230
    {0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //231
    {0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00}, //232
    {0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //233
    {0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, 0x00, 0x00, 0x00, 0x00}, //234
    {0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00}, //235
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //236
    {0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00}, //237
    {0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00}, //238
    {0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //239
    {0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //240
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, //241
    {0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //242
    {0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //243
    {0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //244
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00}, //245
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //246
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //247
    {0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //248
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //249
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //250
    {0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00}, //251
    {0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //252
    {0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //253
    {0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00}, //254
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //255
};

struct nu_ge2d
{
    char                *name;
    IRQn_Type            irqn;
    E_SYS_IPRST          rstidx;
    E_SYS_IPCLK          clkidx;

    rt_mutex_t           lock;
#if defined(DEF_COND_WAIT)
    rt_sem_t             signal;
#endif
};
typedef struct nu_ge2d *nu_ge2d_t;

static struct nu_ge2d g_sNuGe2d =
{
    .name = "GE2D",
    .irqn = IRQ_GE2D,
    .rstidx = GE2DRST,
    .clkidx = GE2DCKEN
};

#define NU_GE2D_LOCK()    { \
                                rt_err_t result = rt_mutex_take(g_sNuGe2d.lock, RT_WAITING_FOREVER); \
                              RT_ASSERT(result == RT_EOK); \
                          }

#define NU_GE2D_UNLOCK()  { \
                                rt_err_t result = rt_mutex_release(g_sNuGe2d.lock); \
                              RT_ASSERT(result == RT_EOK); \
                          }

#if defined(DEF_COND_WAIT)
#define NU_GE2D_COND_WAIT() { \
                                  rt_err_t result = rt_sem_take(g_sNuGe2d.signal, RT_WAITING_FOREVER); \
                                RT_ASSERT(result == RT_EOK); \
                            }

#define NU_GE2D_SIGNAL()  { \
                                rt_err_t result = rt_sem_release(g_sNuGe2d.signal); \
                              RT_ASSERT(result == RT_EOK); \
                          }
/* Interrupt Service Routine for GE2D */
static void nu_ge2d_isr(int vector, void *param)
{
    /* Clear interrupt status. */
    outpw(REG_GE2D_INTSTS, 1);

    /* Signal condition-waiting to resume caller. */
    NU_GE2D_SIGNAL();
}
#else
#define NU_GE2D_COND_WAIT() { \
                                 while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); \
                                 outpw(REG_GE2D_INTSTS, 1); \
                            }
#define NU_GE2D_SIGNAL()
#endif


static unsigned long make_color(int color)
{
    UINT32 r, g, b;

    if (GFX_BPP == 8)
    {
        r = (color & 0x00e00000) >> 16; // 3 bits
        g = (color & 0x0000e000) >> 11; // 3 bits
        b = (color & 0x000000c0) >> 6;  // 2 bits
        return (r | g | b);
    }
    else if (GFX_BPP == 16)
    {
        r = (color & 0x00f80000) >> 8; // 5 bits
        g = (color & 0x0000fc00) >> 5; // 6 bits
        b = (color & 0x000000f8) >> 3; // 5 bits
        return (r | g | b);
    }
    else return (UINT32)color;
}
/// @endcond /* HIDDEN_SYMBOLS */

/**
  * @brief  Clear the on screen buffer with a specified color.
  * @param[in] color clear with this color.
  * @return none
  */
void ge2dClearScreen(int color)
{
    UINT32 cmd32;
    UINT32 color32, dest_pitch, dest_dimension;

    color32 = make_color(color);

    cmd32 = 0xcc430040;
    outpw(REG_GE2D_CTL, cmd32);
    outpw(REG_GE2D_BGCOLR, color32); // fill with background color

    dest_pitch = GFX_WIDTH << 16; // pitch in pixels
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    outpw(REG_GE2D_DSTSPA, 0); // starts from (0,0)

    dest_dimension = GFX_HEIGHT << 16 | GFX_WIDTH;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Set output data mask.
  * @param[in] mask is mask value
  * @return none
  */
void ge2dSetWriteMask(int mask)
{
    outpw(REG_GE2D_WRPLNMSK, make_color(mask));
}

/**
  * @brief Set source origin starting address.
  * @param[in] ptr pointer of start address
  * @return none
  */
void ge2dSetSourceOriginStarting(void *ptr)
{
    outpw(REG_GE2D_XYSORG, (int)ptr);
}

/**
  * @brief Set destination origin starting address.
  * @param[in] ptr pointer of start address
  * @return none
  */
void ge2dSetDestinationOriginStarting(void *ptr)
{
    outpw(REG_GE2D_XYDORG, (int)ptr);
}


/**
  * @brief Reset graphics engine.
  * @param none
  * @return none
  */
void ge2dReset(void)
{
    outpw(REG_GE2D_MISCTL, 0x40); // FIFO reset
    outpw(REG_GE2D_MISCTL, 0x00);

    outpw(REG_GE2D_MISCTL, 0x80); // Engine reset
    outpw(REG_GE2D_MISCTL, 0x00);
}

/**
  * @brief Graphics engine initialization.
  * @param[in] bpp bit per pixel
  * @param[in] width is width of display memory
  * @param[in] height is height of display memory
  * @param[in] destination is pointer of destination buffer address
  * @return none
  */
void ge2dInit(int bpp, int width, int height, void *destination)
{
    UINT32 data32;

    if (destination == NULL)
        return;

    NU_GE2D_LOCK();

    ge2dReset();

    GFX_WIDTH = width;
    GFX_HEIGHT = height;

    _DrawMode = MODE_TRANSPARENT;
    _ColorKey = COLOR_KEY;
    _ColorKeyMask = 0xFFFFFF;

    GFX_START_ADDR = (void *)destination;

    if (GFX_BPP != bpp)
    {
        GFX_BPP = bpp;
        if (GFX_PAT_ADDR != NULL)
        {
            rt_free_align(GFX_PAT_ADDR);
            GFX_PAT_ADDR = RT_NULL;
        }
        if (GFX_PAT_ADDR == NULL)
        {
            uint32_t u32Size = (8 * 8 * (GFX_BPP / 8)) * 2;
            GFX_PAT_ADDR = (void *)rt_malloc_align(u32Size, u32Size);
            RT_ASSERT(GFX_PAT_ADDR != RT_NULL);
            sysprintf("[%s] Allocated %d@0x%08x.\n", __func__, u32Size, GFX_PAT_ADDR);
        }
    }


#ifdef DEBUG
    sysprintf("[%s]\n", __func__);
    sysprintf("screen width = %d\n", GFX_WIDTH);
    sysprintf("screen height = %d\n", GFX_HEIGHT);
    sysprintf("screen bpp = %d\n", GFX_BPP);
    sysprintf("destination = 0x%x\n", destination);
#endif

    outpw(REG_GE2D_INTSTS, 1); // clear interrupt
    outpw(REG_GE2D_PATSA, (unsigned int)GFX_PAT_ADDR);
    outpw(REG_GE2D_CTL, 0); // disable interrupt
    outpw(REG_GE2D_XYDORG, (unsigned int)GFX_START_ADDR);
    outpw(REG_GE2D_XYSORG, (unsigned int)GFX_START_ADDR);

    outpw(REG_GE2D_WRPLNMSK, 0x00ffffff); // write plane mask

    data32 = GE_BPP_8; // default is 8 bpp

    if (GFX_BPP == 16)
    {
        data32 |= GE_BPP_16;
    }
    else if (GFX_BPP == 32)
    {
        data32 |= GE_BPP_32;
    }

    outpw(REG_GE2D_MISCTL, data32);
}

/**
  * @brief Reset FIFO of graphics engine.
  * @param none
  * @return none
  */
void ge2dResetFIFO(void)
{
    UINT32 temp32;

    temp32 = inpw(REG_GE2D_MISCTL);
    temp32 |= 0x00000040;
    outpw(REG_GE2D_MISCTL, temp32);
    temp32 &= 0xffffffbf;
    outpw(REG_GE2D_MISCTL, temp32);
}

/**
  * @brief Set BitBlt drawing mode.
  * @param[in] opt is drawing mode
  * @param[in] ckey is value of color key
  * @param[in] mask is value of color mask
  * @return none
  */
void ge2dBitblt_SetDrawMode(int opt, int ckey, int mask)
{
    if (opt == MODE_TRANSPARENT)
    {
        _DrawMode = MODE_TRANSPARENT;

        _ColorKey = make_color(ckey);
        _ColorKeyMask = make_color(mask);

        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (opt == MODE_DEST_TRANSPARENT)
    {
        _DrawMode = MODE_DEST_TRANSPARENT;

        _ColorKey = make_color(ckey);
        _ColorKeyMask = make_color(mask);

        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else
    {
        _DrawMode = MODE_OPAQUE; // default is OPAQUE
    }
}

/**
  * @brief Set alpha blending programming.
  * @param[in] opt is selection for enable or disable
  * @param[in] ks is value of alpha blending factor Ks
  * @param[in] kd is value of alpha blending factor Kd
  * @return none
  */
int ge2dBitblt_SetAlphaMode(int opt, int ks, int kd)
{
    if (ks + kd > 255)
        return -1;

    if (opt == 1)
    {
        _EnableAlpha = TRUE;
        _AlphaKs = ks;
        _AlphaKd = kd;
    }
    else
    {
        _EnableAlpha = FALSE;
    }

    return 0;
}

/**
  * @brief Screen-to-Screen BitBlt with SRCCOPY ROP operation.
  * @param[in] srcx is source x position
  * @param[in] srcy is source y position
  * @param[in] destx is destination x position
  * @param[in] desty is destination y position
  * @param[in] width is display width
  * @param[in] height is display width
  * @return none
  */
void ge2dBitblt_ScreenToScreen(int srcx, int srcy, int destx, int desty, int width, int height)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_to_screen_blt():\n");
    sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    cmd32 = 0xcc430000;

    outpw(REG_GE2D_CTL, cmd32);

    if (srcx > destx)   //+X
    {
        if (srcy > desty)   //+Y
        {
        }
        else     //-Y
        {
            cmd32 |= 0x08;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }
    else     //-X
    {
        if (srcy > desty)   //+Y
        {
            cmd32 |= 0x04; // 010
            srcx = srcx + width - 1;
            destx = destx + width - 1;
        }
        else     //-Y
        {
            cmd32 |= 0xc; // 110
            srcx = srcx + width - 1;
            destx = destx + width - 1;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }

#ifdef DEBUG
    sysprintf("new srcx=%d srcy=%d\n", srcx, srcy);
    sysprintf("new destx=%d desty=%d\n", destx, desty);
#endif

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | GFX_WIDTH;
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = srcy << 16 | srcx;
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    //
    // force to use the same starting address
    //
    outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR);
    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);  //smf

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Screen-to-Screen BitBlt with ROP option.
  * @param[in] srcx is source x position
  * @param[in] srcy is source y position
  * @param[in] destx is destination x position
  * @param[in] desty is destination y position
  * @param[in] width is display width
  * @param[in] height is display width
  * @param[in] rop is rop option
  * @return none
  */
void ge2dBitblt_ScreenToScreenRop(int srcx, int srcy, int destx, int desty, int width, int height, int rop)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_to_screen_rop_blt():\n");
    sysprintf("ROP=0x%x\n", rop);
    sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    cmd32 = 0x00430000 | (rop << 24);

    if (_PatternType == TYPE_MONO)
    {
        cmd32 |= 0x00000010; // default is TYPE_COLOR
    }

    outpw(REG_GE2D_CTL, cmd32);

    if (srcx > destx)   //+X
    {
        if (srcy > desty)   //+Y
        {
        }
        else     //-Y
        {
            cmd32 |= 0x08;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }
    else     //-X
    {
        if (srcy > desty)   //+Y
        {
            cmd32 |= 0x04; // 010
            srcx = srcx + width - 1;
            destx = destx + width - 1;
        }
        else     //-Y
        {
            cmd32 |= 0xc; // 110
            srcx = srcx + width - 1;
            destx = destx + width - 1;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }

#ifdef DEBUG
    sysprintf("new srcx=%d srcy=%d\n", srcx, srcy);
    sysprintf("new destx=%d desty=%d\n", destx, desty);
#endif

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | GFX_WIDTH; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = srcy << 16 | srcx;
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    //
    // force to use the same starting address
    //
    outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR);
    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);  //smf

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    if ((rop == 0x00) || (rop == 0xff))
    {
        cmd32 = (cmd32 & 0xffff0fff) | 0x00009000;
        outpw(REG_GE2D_CTL, cmd32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Source to destination BitBlt with SRCCOPY ROP operation.
  * @param[in] srcx is source x position
  * @param[in] srcy is source y position
  * @param[in] destx is destination x position
  * @param[in] desty is destination y position
  * @param[in] width is display width
  * @param[in] height is display width
  * @param[in] srcpitch is source pixel pitch
  * @param[in] destpitch is destination pixel pitch
  * @return none
  * @note before calling this function, it would set the source and destination origin starting place
  */
void ge2dBitblt_SourceToDestination(int srcx, int srcy, int destx, int desty, int width, int height, int srcpitch, int destpitch)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("source_to_destination_blt():\n");
    sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    cmd32 = 0xcc430000;

    outpw(REG_GE2D_CTL, cmd32);

    if (srcx > destx)   //+X
    {
        if (srcy > desty)   //+Y
        {
        }
        else     //-Y
        {
            cmd32 |= 0x08;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }
    else     //-X
    {
        if (srcy > desty)   //+Y
        {
            cmd32 |= 0x04; // 010
            srcx = srcx + width - 1;
            destx = destx + width - 1;
        }
        else     //-Y
        {
            cmd32 |= 0xc; // 110
            srcx = srcx + width - 1;
            destx = destx + width - 1;
            srcy = srcy + height - 1;
            desty = desty + height - 1;
        }
    }

#ifdef DEBUG
    sysprintf("new srcx=%d srcy=%d\n", srcx, srcy);
    sysprintf("new destx=%d desty=%d\n", destx, desty);
#endif

    outpw(REG_GE2D_CTL, cmd32);

    pitch = destpitch << 16 | srcpitch; // pitch in pixel, back | GFX_WIDTH ??
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = srcy << 16 | srcx;
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);


    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Set the clip rectangle. (top-left to down-right).
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @return none
  */
void ge2dClip_SetClip(int x1, int y1, int x2, int y2)
{

#ifdef DEBUG
    sysprintf("set_clip(): (%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
#endif

    if ((x1 >= 0) && (y1 >= 0) && (x2 >= 0) && (y2 >= 0))
    {
        if ((x2 > x1) && (y2 > y1))
        {
            _ClipEnable = TRUE;
            /* hardware clipper not includes last pixel */
            x2++;
            y2++;
            _ClipTL = (UINT32)((y1 << 16) | x1);
            _ClipBR = (UINT32)((y2 << 16) | x2);
        }
        else
        {
            _ClipEnable = FALSE;
        }
    }
    else
    {
        _ClipEnable = FALSE;
    }
}

/**
  * @brief Set the clip to inside clip or outside clip.
  * @param[in] opt is option for setting clip inside or outside, value could be
  *                                 - \ref MODE_INSIDE_CLIP
  *                                 - \ref MODE_OUTSIDE_CLIP
  * @return none
  */
void ge2dClip_SetClipMode(int opt)
{
    _OutsideClip = (opt == 0) ? FALSE : TRUE;

    if (_OutsideClip)
    {
#ifdef DEBUG
        sysprintf("set_clip_mode(): OUTSIDE\n");
#endif
    }
    else
    {
#ifdef DEBUG
        sysprintf("set_clip_mode(): INSIDE\n");
#endif
    }
}

/**
  * @brief Draw an one-pixel rectangle frame.
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @param[in] color is color of this rectangle
  * @param[in] opt is draw option, value could be
  *                                - 0: rectangle
  *                                - 1: diagonal
  * @return none
  */
void ge2dDrawFrame(int x1, int y1, int x2, int y2, int color, int opt)
{
    UINT32 dest_pitch, dest_start, dest_dimension;
    UINT32 color32;

#ifdef DEBUG
    sysprintf("draw_frame():\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
    sysprintf("color=0x%x opt=%d\n", color, opt);
#endif

    /*
    ** The opt==1 case must be specially handled.
    */

    if (opt == 0)
    {
        outpw(REG_GE2D_CTL, 0xcccb0000); // rectangle
    }
    else
    {
        outpw(REG_GE2D_CTL, 0xcccf0000); // diagonal
    }

#ifdef DEBUG
    sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
#endif

    color32 = make_color(color);
    outpw(REG_GE2D_FGCOLR, color32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = y1 << 16 | x1;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = (y2 - y1) << 16 | (x2 - x1);
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_MISCTL, inpw(REG_GE2D_MISCTL)); // address caculation

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Draw an solid rectangle line.
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @param[in] color is color of this line
  * @return none
  */
void ge2dLine_DrawSolidLine(int x1, int y1, int x2, int y2, int color)
{
    int abs_X, abs_Y, min, max;
    UINT32 step_constant, initial_error, direction_code;
    UINT32 cmd32, dest_pitch, dest_start;

#ifdef DEBUG
    sysprintf("draw_solid_line():\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
    sysprintf("color=0x%x\n", color);
#endif

    abs_X = ABS(x2 - x1); //absolute value
    abs_Y = ABS(y2 - y1); //absolute value
    if (abs_X > abs_Y)    // X major
    {
        max = abs_X;
        min = abs_Y;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpXl;
            else // -Y direction
                direction_code = XpYmXl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpXl;
            else // -Y direction
                direction_code = XmYmXl;
        }
    }
    else     // Y major
    {
        max = abs_Y;
        min = abs_X;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpYl;
            else // -Y direction
                direction_code = XpYmYl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpYl;
            else // -Y direction
                direction_code = XmYmYl;
        }
    }

    outpw(REG_GE2D_BETSC, step_constant);
    outpw(REG_GE2D_BIEPC, initial_error);

    cmd32 = 0x008b0000 | direction_code;

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_BGCOLR, make_color(color));
    outpw(REG_GE2D_FGCOLR, make_color(color));

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    dest_start = y1 << 16 | x1;
    outpw(REG_GE2D_DSTSPA, dest_start);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Draw an solid rectangle line with assigned RGB565 color
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @param[in] color is color of this line
  * @return none
  */
void ge2dLine_DrawSolidLine_RGB565(int x1, int y1, int x2, int y2, int color)
{
    int abs_X, abs_Y, min, max;
    UINT32 step_constant, initial_error, direction_code;
    UINT32 cmd32, dest_pitch, dest_start;

#ifdef DEBUG
    sysprintf("draw_solid_line():\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2);
    sysprintf("color=0x%x\n", color);
#endif

    abs_X = ABS(x2 - x1); //absolute value
    abs_Y = ABS(y2 - y1); //absolute value
    if (abs_X > abs_Y)    // X major
    {
        max = abs_X;
        min = abs_Y;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpXl;
            else // -Y direction
                direction_code = XpYmXl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpXl;
            else // -Y direction
                direction_code = XmYmXl;
        }
    }
    else     // Y major
    {
        max = abs_Y;
        min = abs_X;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpYl;
            else // -Y direction
                direction_code = XpYmYl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpYl;
            else // -Y direction
                direction_code = XmYmYl;
        }
    }

    outpw(REG_GE2D_BETSC, step_constant);
    outpw(REG_GE2D_BIEPC, initial_error);

    cmd32 = 0x008b0000 | direction_code;

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_BGCOLR, color);
    outpw(REG_GE2D_FGCOLR, color);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    dest_start = y1 << 16 | x1;
    outpw(REG_GE2D_DSTSPA, dest_start);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}


/**
  * @brief Draw a styled line.
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @param[in] style is style of line pattern
  * @param[in] fgcolor is color of foreground
  * @param[in] bkcolor is color of background
  * @param[in] draw_mode is transparent is enable or not
  * @return none
  */
void ge2dLine_DrawStyledLine(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode)
{
    int abs_X, abs_Y, min, max;
    UINT32 step_constant, initial_error, direction_code;
    UINT32 cmd32, dest_pitch, dest_start;
    UINT32 temp32, line_control_code;

    abs_X = ABS(x2 - x1);
    abs_Y = ABS(y2 - y1);
    if (abs_X > abs_Y)   // X major
    {
        max = abs_X;
        min = abs_Y;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpXl;
            else // -Y direction
                direction_code = XpYmXl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpXl;
            else // -Y direction
                direction_code = XmYmXl;
        }
    }
    else     // Y major
    {
        max = abs_Y;
        min = abs_X;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpYl;
            else // -Y direction
                direction_code = XpYmYl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpYl;
            else // -Y direction
                direction_code = XmYmYl;
        }
    }

    outpw(REG_GE2D_BETSC, step_constant);
    outpw(REG_GE2D_BIEPC, initial_error);

    cmd32 = 0x009b0000 | direction_code; // styled line
    if (draw_mode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // default is MODE_OPAQUE
    }
    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_BGCOLR, make_color(bkcolor));
    outpw(REG_GE2D_FGCOLR, make_color(fgcolor));

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    dest_start = y1 << 16 | x1;
    outpw(REG_GE2D_DSTSPA, dest_start);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    line_control_code = style;
    temp32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
    temp32 = (line_control_code << 16) | temp32;

    outpw(REG_GE2D_MISCTL, temp32); // address caculation

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Draw a styled line using RGB565 color
  * @param[in] x1 is top-left x position
  * @param[in] y1 is top-left y position
  * @param[in] x2 is down-right x position
  * @param[in] y2 is down-right y position
  * @param[in] style is style of line pattern
  * @param[in] fgcolor is color of foreground
  * @param[in] bkcolor is color of background
  * @param[in] draw_mode is transparent is enable or not
  * @return none
  */
void ge2dLine_DrawStyledLine_RGB565(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode)
{
    int abs_X, abs_Y, min, max;
    UINT32 step_constant, initial_error, direction_code;
    UINT32 cmd32, dest_pitch, dest_start;
    UINT32 temp32, line_control_code;

    abs_X = ABS(x2 - x1);
    abs_Y = ABS(y2 - y1);
    if (abs_X > abs_Y)   // X major
    {
        max = abs_X;
        min = abs_Y;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpXl;
            else // -Y direction
                direction_code = XpYmXl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpXl;
            else // -Y direction
                direction_code = XmYmXl;
        }
    }
    else     // Y major
    {
        max = abs_Y;
        min = abs_X;

        step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min);
        initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max);

        if (x2 > x1)   // +X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XpYpYl;
            else // -Y direction
                direction_code = XpYmYl;
        }
        else     // -X direction
        {
            if (y2 > y1) // +Y direction
                direction_code = XmYpYl;
            else // -Y direction
                direction_code = XmYmYl;
        }
    }

    outpw(REG_GE2D_BETSC, step_constant);
    outpw(REG_GE2D_BIEPC, initial_error);

    cmd32 = 0x009b0000 | direction_code; // styled line
    if (draw_mode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // default is MODE_OPAQUE
    }
    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_BGCOLR, bkcolor);
    outpw(REG_GE2D_FGCOLR, fgcolor);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    dest_start = y1 << 16 | x1;
    outpw(REG_GE2D_DSTSPA, dest_start);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    line_control_code = style;
    temp32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
    temp32 = (line_control_code << 16) | temp32;

    outpw(REG_GE2D_MISCTL, temp32); // address caculation

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle solid color fill with foreground color.
  * @param[in] dx x position
  * @param[in] dy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] color is color of foreground
  * @return none
  */
void ge2dFill_Solid(int dx, int dy, int width, int height, int color)
{
    UINT32 cmd32, color32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("solid_fill() begin\n");
    sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1);
    sysprintf("color=0x%x\n", color);
#endif

    color32 = make_color(color);
    cmd32 = 0xcc430060;
    outpw(REG_GE2D_CTL, cmd32);
    outpw(REG_GE2D_FGCOLR, color32); // fill with foreground color

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = dy << 16 | dx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle solid color fill with RGB565 color.
  * @param[in] dx x position
  * @param[in] dy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] color is RGB565 color of foreground
  * @return none
  */
void ge2dFill_Solid_RGB565(int dx, int dy, int width, int height, int color)
{
    UINT32 cmd32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("solid_fill()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1);
    sysprintf("color=0x%x\n", color);
#endif

    cmd32 = 0xcc430060;
    outpw(REG_GE2D_CTL, cmd32);
    outpw(REG_GE2D_FGCOLR, color); // fill with foreground color

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = dy << 16 | dx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle solid color fill with background color.
  * @param[in] dx x position
  * @param[in] dy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] color is color of background
  * @return none
  */
void ge2dFill_SolidBackground(int dx, int dy, int width, int height, int color)
{
    UINT32 cmd32, color32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("solid_fill_back()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1);
    sysprintf("color=0x%x\n", color);
#endif

    color32 = make_color(color);

    cmd32 = 0xcc430040;
    outpw(REG_GE2D_CTL, cmd32);
    outpw(REG_GE2D_BGCOLR, color32); // fill with foreground color

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = dy << 16 | dx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle fill with 8x8 color pattern.
  * @param[in] dx x position
  * @param[in] dy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @return none
  * @note The color pattern data is stored in the off-screen buffer.
  */
void ge2dFill_ColorPattern(int dx, int dy, int width, int height)
{
    UINT32 cmd32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("color_pattern_fill()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1);
    sysprintf("pattern offset (%d,%d)\n", dx % 8, dy % 8);
#endif

    cmd32 = 0xf0430000;
    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = dy << 16 | dx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle fill with 8x8 mono pattern.
  * @param[in] dx x position
  * @param[in] dy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] opt is transparent is enable or not
  * @return none
  */
void ge2dFill_MonoPattern(int dx, int dy, int width, int height, int opt)
{
    UINT32 cmd32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("mono_pattern_fill()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1);
#endif

    cmd32 = 0xf0430010;
    if (opt == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00006000;
    }
    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = dy << 16 | dx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle fill with 8x8 color pattern.
  * @param[in] sx x position
  * @param[in] sy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] rop is ROP operation code
  * @return none
  */
void ge2dFill_ColorPatternROP(int sx, int sy, int width, int height, int rop)
{
    UINT32 cmd32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("color_pattern_fill()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", sx, sy, sx + width - 1, sy + height - 1);
    sysprintf("pattern offset (%d,%d)\n", sx % 8, sy % 8);
#endif

    cmd32 = 0x00430000 | (rop << 24);
    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = sy << 16 | sx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Rectangle fill with 8x8 mono pattern.
  * @param[in] sx x position
  * @param[in] sy y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] opt is transparent is enable or not
  * @param[in] rop is ROP operation code
  * @return none
  */
void ge2dFill_MonoPatternROP(int sx, int sy, int width, int height, int rop, int opt)
{
    UINT32 cmd32;
    UINT32 dest_start, dest_pitch, dest_dimension;

#ifdef DEBUG
    sysprintf("mono_pattern_fill()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", sx, sy, sx + width - 1, sy + height - 1);
#endif

    cmd32 = 0x00430010 | (rop << 24);
    if (opt == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00006000;
    }
    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = sy << 16 | sx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief TileBLT function.
  * @param[in] srcx source x position
  * @param[in] srcy source y position
  * @param[in] destx destination x position
  * @param[in] desty destination y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] x_count is tile count for x-axis
  * @param[in] y_count is tile count for y-axis
  * @return none
  */
void ge2dFill_TileBlt(int srcx, int srcy, int destx, int desty, int width, int height, int x_count, int y_count)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 tile_ctl;

#ifdef DEBUG
    sysprintf("tile_blt_image()\n");
    sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty);
    sysprintf("width=%d height=%d\n", width, height);
    sysprintf("%dx%d grids\n", x_count, y_count);
#endif

    if (x_count > 0) x_count--;
    if (y_count > 0) y_count--;

    cmd32 = 0xcc430400; // b10 is the tile control

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | GFX_WIDTH; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = srcy << 16 | srcx;           // redundancy ??
    outpw(REG_GE2D_SRCSPA, src_start);  // redundancy ??

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    tile_ctl = (y_count << 8) | (x_count);
    outpw(REG_GE2D_TCNTVHSF, tile_ctl);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Host-to-Screen BitBlt with SRCCOPY (through data port)
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] buf is pointer of HostBLT data
  * @return none
  */
void ge2dHostBlt_Write(int x, int y, int width, int height, void *buf)
{
    UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
    int transfer_count, i, j;
    UINT32 *ptr32, data32;

#ifdef DEBUG
    sysprintf("host_write_blt()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    cmd32 = 0xcc430020;

    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_TRG, 1);

    ptr32 = (UINT32 *)buf;
    for (i = 0; i < height; i++) // 120
    {
        transfer_count = (width * (GFX_BPP / 8) + 3) / 4; // 4-byte count

        while (transfer_count >= 8)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < 8; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
            transfer_count -= 8;
        }

        if (transfer_count > 0)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < transfer_count; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
        }
    }

    while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); // wait for command complete
    outpw(REG_GE2D_INTSTS, 1); // clear interrupt status
}

/**
  * @brief Screen-to-Host BitBlt with SRCCOPY (through data port).
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] buf is pointer of HostBLT data
  * @return none
  */
void ge2dHostBlt_Read(int x, int y, int width, int height, void *buf)
{
    UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
    int transfer_count, i, j;
    UINT32 *ptr32;

#ifdef DEBUG
    sysprintf("host_read_blt()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    cmd32 = 0xcc430001;

    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_TRG, 1);

    ptr32 = (UINT32 *)buf;
    for (i = 0; i < height; i++)
    {
        transfer_count = (width * (GFX_BPP / 8) + 3) / 4; // 4-byte count

        while (transfer_count >= 8)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000400) == 0);
            for (j = 0; j < 8; j++)
            {
                *ptr32++ = inpw(REG_GE2D_GEHBDW0);
            }
            transfer_count -= 8;
        }

        if (transfer_count > 0)
        {
            while (((inpw(REG_GE2D_MISCTL) & 0x0000f000) >> 12) != transfer_count);
            for (j = 0; j < transfer_count; j++)
            {
                *ptr32++ = inpw(REG_GE2D_GEHBDW0);
            }
        }
    }

    while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); // wait for command complete

    outpw(REG_GE2D_INTSTS, 1); // clear interrupt status
}

/**
  * @brief Host-to-Screen SpriteBlt with SRCCOPY.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] buf is pointer of HostBLT data
  * @return none
  */
void ge2dHostBlt_Sprite(int x, int y, int width, int height, void *buf)
{
    UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
    int transfer_count, i, j;
    UINT32 *ptr32, data32, alpha;

#ifdef DEBUG
    sysprintf("host_sprite_blt()\n");
    sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1);
#endif

    cmd32 = 0xcc430020;

    outpw(REG_GE2D_CTL, cmd32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    outpw(REG_GE2D_TRG, 1);

    ptr32 = (UINT32 *)buf;
    for (i = 0; i < height; i++)
    {
        transfer_count = width * (GFX_BPP / 8) / 4; // 4-byte count

        while (transfer_count > 8)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < 8; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
            transfer_count -= 8;
        }

        if (transfer_count > 0)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < transfer_count; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
        }
    }

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Captured the specified photo data from display memory, then displayed on display memory by rotation angle
  * @param[in] srcx source x position
  * @param[in] srcy source y position
  * @param[in] destx destination x position
  * @param[in] desty destination y position
  * @param[in] width is display width
  * @param[in] height is display height
  * @param[in] ctl is drawing direction
  * @return none
  */
void ge2dRotation(int srcx, int srcy, int destx, int desty, int width, int height, int ctl)
{
    UINT32 cmd32, dest_start, src_start, dimension, pitch;
    void *tmpscreen, *orig_dest_start00;

    tmpscreen = (void *)rt_malloc(width * height * GFX_BPP / 8);

#ifdef DEBUG
    sysprintf("rotation_image()\n");
    sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty);
    sysprintf("width=%d height=%d\n", width, height);
#endif

    rt_memset(tmpscreen, 0, width * height * GFX_BPP / 8);

    orig_dest_start00 = (void *)inpw(REG_GE2D_XYDORG);
    outpw(REG_GE2D_XYDORG, (int)tmpscreen);   //captured photo to another position
    outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR);

    ge2dBitblt_SourceToDestination(srcx, srcy, 0, 0, width, height, GFX_WIDTH, width);

    src_start = dest_start = dimension = cmd32 = pitch = 0;

    outpw(REG_GE2D_XYDORG, (int)orig_dest_start00);
    outpw(REG_GE2D_XYSORG, (int)tmpscreen);

    pitch = GFX_WIDTH << 16 | width;
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = 0 << 16 | 0;  // captured photo at (0,0) position
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    cmd32 = 0xcc030000 | (ctl << 1);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    /* set rotation reference point xy register, then nothing happened */
    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    rt_free(tmpscreen);

    NU_GE2D_UNLOCK();
}

/**
  * @brief OffScreen-to-OnScreen SpriteBlt with SRCCOPY.
  * @param[in] destx destination x position
  * @param[in] desty destination y position
  * @param[in] sprite_width is sprite width
  * @param[in] sprite_height is sprite height
  * @param[in] buf is pointer of origin data
  * @return none
  */
void ge2dSpriteBlt_Screen(int destx, int desty, int sprite_width, int sprite_height, void *buf)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_sprite_blt():\n");
    sysprintf("buf=%08x, x=%d y=%d width=%d height=%d\n", buf, destx, desty, sprite_width, sprite_height);
#endif

    cmd32 = 0xcc430000;

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = 0; // start from (0,0) of sprite
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = desty << 16 | destx;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = sprite_height << 16 | sprite_width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    outpw(REG_GE2D_XYSORG, (UINT32)buf);
    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }


    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }


    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief OffScreen-to-OnScreen SpriteBlt with SRCCOPY.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] sprite_sx sprite x position
  * @param[in] sprite_sy sprite y position
  * @param[in] width is width
  * @param[in] height is height
  * @param[in] sprite_width is sprite width
  * @param[in] sprite_height is sprite height
  * @param[in] buf is pointer of origin data
  * @return none
  * @note The sprite starting address can be programmed.
  */
void ge2dSpriteBltx_Screen(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_sprite_bltx(): (%d,%d)\n", x, y);
    sysprintf("sprite width=%d height=%d\n", sprite_width, sprite_height);
    sysprintf("x=%d y=%d width=%d height=%d\n", sprite_sx, sprite_sy, width, height);
#endif

    cmd32 = 0xcc430000;

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    outpw(REG_GE2D_XYSORG, (UINT32)buf);
    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);

    src_start = sprite_sy << 16 | sprite_sx;
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief OffScreen-to-OnScreen SpriteBlt with ROP.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] sprite_width is sprite width
  * @param[in] sprite_height is sprite height
  * @param[in] buf is pointer of origin data
  * @param[in] rop is ROP operation code
  * @return none
  * @note The sprite always starts from (0,0) for the BLT.
  */
void ge2dSpriteBlt_ScreenRop(int x, int y, int sprite_width, int sprite_height, void *buf, int rop)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_sprite_rop_blt():\n");
    sysprintf("x=%d y=%d width=%d height=%d\n", x, y, sprite_width, sprite_height);
    sysprintf("rop=0x%x\n", rop);
#endif

    cmd32 = 0x00430000 | (rop << 24);

    if (_PatternType == TYPE_MONO)
    {
        cmd32 |= 0x00000010; // default is TYPE_COLOR
    }

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = 0; // start from (0,0) of sprite
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = sprite_height << 16 | sprite_width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    outpw(REG_GE2D_XYSORG, (UINT32)buf);
    outpw(REG_GE2D_XYDORG, (int) GFX_START_ADDR); //smf

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    if ((rop == 0x00) || (rop == 0xff))
    {
        cmd32 = (cmd32 & 0xffff0fff) | 0x00009000;
        outpw(REG_GE2D_CTL, cmd32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief OffScreen-to-OnScreen SpriteBlt with ROP.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] sprite_sx sprite x position
  * @param[in] sprite_sy sprite y position
  * @param[in] width is width
  * @param[in] height is height
  * @param[in] sprite_width is sprite width
  * @param[in] sprite_height is sprite height
  * @param[in] buf is pointer of origin data
  * @param[in] rop is ROP operation code
  * @return none
  * @note The sprite always starts from (0,0) for the BLT.
  */
void ge2dSpriteBltx_ScreenRop(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf, int rop)
{
    UINT32 cmd32, pitch, dest_start, src_start, dimension;
    UINT32 data32, alpha;

#ifdef DEBUG
    sysprintf("screen_sprite_rop_bltx():\n");
    sysprintf("x=%d y=%d width=%d height=%d\n", x, y, sprite_width, sprite_height);
    sysprintf("rop=0x%x\n", rop);
#endif

    cmd32 = 0x00430000 | (rop << 24);

    if (_PatternType == TYPE_MONO)
    {
        cmd32 |= 0x00000010; // default is TYPE_COLOR
    }

    outpw(REG_GE2D_CTL, cmd32);

    pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, pitch);

    src_start = sprite_sy << 16 | sprite_sx;
    outpw(REG_GE2D_SRCSPA, src_start);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dimension);

    outpw(REG_GE2D_XYSORG, (UINT32)buf);
    outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR);  //smf

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    if (_DrawMode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00008000; // color transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }
    else if (_DrawMode == MODE_DEST_TRANSPARENT)
    {
        cmd32 |= 0x00009000;   // destination pixels control transparency
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_TRNSCOLR, _ColorKey);
        outpw(REG_GE2D_TCMSK, _ColorKeyMask);
    }

    if (_EnableAlpha)
    {
        cmd32 |= 0x00200000;
        outpw(REG_GE2D_CTL, cmd32);

        data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff;
        alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd);
        data32 |= (alpha << 16);

        outpw(REG_GE2D_MISCTL, data32);
    }

    if ((rop == 0x00) || (rop == 0xff))
    {
        cmd32 = (cmd32 & 0xffff0fff) | 0x00009000;
        outpw(REG_GE2D_CTL, cmd32);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief OffScreen-to-OnScreen TextBLT.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] width is width
  * @param[in] height is height
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @param[in] opt is transparent is enable or not
  * @param[in] buf is pointer of origin data
  * @return none
  * @note Fetch the monochrome source data from off-screen memory to the desired destination area
  */
void ge2dColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf)
{
    UINT32 cmd32, dest_pitch, src_pitch, pitch, dest_start, dest_dimension;
    UINT32 fore_color32, back_color32;

    fore_color32 = make_color(fore_color);
    back_color32 = make_color(back_color);

    cmd32 = 0xcc430080;
    if (opt == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00004000; // mono transparency
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_FGCOLR, fore_color32);
    outpw(REG_GE2D_BGCOLR, back_color32);

    dest_pitch = GFX_WIDTH; // pitch in pixels
    src_pitch = width; // pitch in pixels

    pitch = (dest_pitch << 16) | src_pitch;
    outpw(REG_GE2D_SDPITCH, pitch);

    outpw(REG_GE2D_XYSORG, (int)buf);
    outpw(REG_GE2D_SRCSPA, 0); // always start from (0,0)

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    if (_ClipEnable)
    {
        cmd32 |= 0x00000200;
        if (_OutsideClip)
        {
            cmd32 |= 0x00000100;
        }
        outpw(REG_GE2D_CTL, cmd32);
        outpw(REG_GE2D_CLPBTL, _ClipTL);
        outpw(REG_GE2D_CLPBBR, _ClipBR);
    }

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Host-to-Screen TextBLT through data port.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] width is width
  * @param[in] height is height
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @param[in] opt is transparent is enable or not
  * @param[in] buf is pointer of origin data
  * @return none
  */
void ge2dHostColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf)
{
    UINT32 cmd32, dest_pitch, dest_start, dest_dimension;
    UINT32 fore_color32, back_color32;
    UINT32 *ptr32, data32;
    int transfer_count, i, j;

    fore_color32 = make_color(fore_color);
    back_color32 = make_color(back_color);

    cmd32 = 0xcc4300a0;
    if (opt == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00004000; // mono transparency
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_FGCOLR, fore_color32);
    outpw(REG_GE2D_BGCOLR, back_color32);

    dest_pitch = GFX_WIDTH << 16; // pitch in pixel
    outpw(REG_GE2D_SDPITCH, dest_pitch);

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);
    outpw(REG_GE2D_SRCSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_TRG, 1);

    ptr32 = (UINT32 *)buf;
    for (i = 0; i < height; i++)
    {
        transfer_count = (width + 31) / 32; // 32 pixels unit

        while (transfer_count > 8)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < 8; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
            transfer_count -= 8;
        }

        if (transfer_count > 0)
        {
            while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty
            for (j = 0; j < transfer_count; j++)
            {
                data32 = *ptr32++;
                outpw(REG_GE2D_GEHBDW0, data32);
            }
        }
    }

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Set the 8x8 mono pattern for following BitBLT functions.
  * @param[in] opt is index for build-in pattern
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @return none
  */
void ge2dInitMonoPattern(int opt, int fore_color, int back_color)
{
    UINT32 color32;

    /*
    ** If hardware pattern definition is a little different from software.
    ** Need to do the BYTE swap before programming the pattern registers.
    */

    outpw(REG_GE2D_PTNA, MonoPatternData[opt].PatternA);
    outpw(REG_GE2D_PTNB, MonoPatternData[opt].PatternB);

    color32 = make_color(fore_color);
    outpw(REG_GE2D_FGCOLR, color32);

    color32 = make_color(back_color);
    outpw(REG_GE2D_BGCOLR, color32);

    _PatternType = TYPE_MONO;
}

/**
  * @brief Set the 8x8 mono pattern for following BitBLT functions.
  * @param[in] PatternA is pattern A
  * @param[in] PatternB is pattern B
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @return none
  */
void ge2dInitMonoInputPattern(UINT32 PatternA, UINT32 PatternB, int fore_color, int back_color)
{
    UINT32 color32;

    /*
    ** If hardware pattern definition is a little different from software.
    ** Need to do the BYTE swap before programming the pattern registers.
    */

    outpw(REG_GE2D_PTNA, PatternA);
    outpw(REG_GE2D_PTNB, PatternB);

    color32 = make_color(fore_color);
    outpw(REG_GE2D_FGCOLR, color32);

    color32 = make_color(back_color);
    outpw(REG_GE2D_BGCOLR, color32);

    _PatternType = TYPE_MONO;
}

/**
  * @brief Set the 8x8 color pattern for following BitBLT functions.
  * @param[in] patformat is format of pattern, value could be
  *                                     - \ref RGB888
  *                                     - \ref RGB565
  *                                     - \ref RGB332
  * @param[in] patdata is pointer of input pattern image
  * @return none
  * @note This function transfers those forms:
  *   RGB888 to RGB565 or RGB332
  *   RGB565 to RGB332 or RGB888
  *   RGB332 to RGB565 or RGB888
  */
void ge2dInitColorPattern(int patformat, void *patdata)
{
    UINT8 *ptr_pat;
    UINT8 *ptr8, r8, g8, b8;
    UINT16 *ptr16, r16, g16, b16, g16_1, g16_2;
    UINT32 *ptr32, r32, g32, b32, g32_1, g32_2;
    int idx;

    ptr_pat = (UINT8 *)patdata;
    if (patformat == RGB888)
    {
        if (GFX_BPP == 8)
        {
            ptr8 = (UINT8 *)GFX_PAT_ADDR;
            for (idx = 0; idx < 64; idx++)
            {
                b8 = (UINT8)(*ptr_pat++) & 0xc0; // 2 bits
                g8 = (UINT8)(*ptr_pat++) & 0xe0; // 3 bits
                r8 = (UINT8)(*ptr_pat++) & 0xe0; // 3 bits
                ptr_pat++;
                *ptr8++ = r8 | (g8 >> 3) | (b8 >> 6);
            }
        }
        else if (GFX_BPP == 16)
        {
            ptr16 = (UINT16 *)GFX_PAT_ADDR;
            for (idx = 0; idx < 64; idx++)
            {
                b16 = (UINT16)(*ptr_pat++) & 0x000f8; // 5 bits
                g16 = (UINT16)(*ptr_pat++) & 0x000fc; // 6 bits
                r16 = (UINT16)(*ptr_pat++) & 0x000f8; // 5 bits
                ptr_pat++;
                *ptr16++ = (r16 << 8) | (g16 << 3) | (b16 >> 3);
            }
        }
        else if (GFX_BPP == 32)
        {
            ptr32 = (UINT32 *)GFX_PAT_ADDR;
            for (idx = 0; idx < 64; idx++)
            {
                b32 = (UINT32)(*ptr_pat++);
                g32 = (UINT32)(*ptr_pat++);
                r32 = (UINT32)(*ptr_pat++);
                ptr_pat++;
                *ptr32++ = (r32 << 16) | (g32 << 8) | b32;
            }
        }
    }
    else if (patformat == RGB565)
    {
        if (GFX_BPP == 8)
        {
            ptr8 = (UINT8 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                b8 = (UINT8)(*ptr_pat++) & 0x00018; // 2 bits
                g8 = (UINT8)(*ptr_pat) & 0x00007;  // 3 bits
                r8 = (UINT8)(*ptr_pat++) & 0x000e0;  // 3bits
                *ptr8++ = r8 | (g8 << 2) | (b8 >> 3);
            }
        }
        else if (GFX_BPP == 16)
        {
            ptr16 = (UINT16 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                *ptr16++ = (*ptr_pat) | (*(ptr_pat + 1)) << 8;
                ptr_pat += 2;
            }
        }
        else if (GFX_BPP == 32)
        {
            ptr32 = (UINT32 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                b32 = (UINT8)(*ptr_pat) & 0x1f;      // 5 bits
                g32_1 = (UINT8)(*ptr_pat++) & 0xe0;  // front 3 bits
                g32_2 = (UINT8)(*ptr_pat) & 0x07;    // back 3 bits
                g32 = ((g32_1 >> 5) | (g32_2 << 3)) << 2;
                r32 = (UINT8)(*ptr_pat++) & 0xf8;    // 5 bits
                *ptr32++ = 0 << 24 | (r32 << 16) | (g32 << 8) | (b32 << 3);
            }
        }
    }
    else if (patformat == RGB332)
    {
        if (GFX_BPP == 8)
        {
            ptr8 = (UINT8 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                *ptr8++ = *ptr_pat;
                ptr_pat++;
            }
        }
        else if (GFX_BPP == 16)
        {
            ptr16 = (UINT16 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                r16 = (UINT8)(*ptr_pat) & 0xe0; // 3 bits
                g16_1 = (UINT8)(*ptr_pat) & 0x10;
                g16_2 = (UINT8)(*ptr_pat) & 0x0c;
                g16 = (g16_1 >> 2) | (g16_2 >> 2);
                b16 = (UINT8)(*ptr_pat++) & 0x3; // 2 bits
                *ptr16++ = (r16 << 8) | (g16 << 8) | (b16 << 3);
            }
        }
        else if (GFX_BPP == 32)
        {
            ptr32 = (UINT32 *)GFX_PAT_ADDR;

            for (idx = 0; idx < 64; idx++)
            {
                r32 = (UINT8)(*ptr_pat) & 0xe0;  // 3 bits
                g32 = (UINT8)(*ptr_pat) & 0x1c;  // 3 bits
                b32 = (UINT8)(*ptr_pat++) & 0x3;  // 2 bits
                *ptr32++ = 0 << 24 | (r32 << 15) | (g32 << 11) | (b32 << 6);
            }
        }
    }

    _PatternType = TYPE_COLOR;
}

/**
  * @brief Display font character.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] asc_code is ascii code
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @param[in] draw_mode is transparent is enable or not
  * @param[in] font_id is selection of 8x8 or 8x16 font
  * @return none
  */
void ge2dFont_PutChar(int x, int y, char asc_code, int fore_color, int back_color, int draw_mode, int font_id)
{
    int cmd32, dest_pitch, src_pitch, pitch, dest_start, dest_dimension;
    UINT32 width, height;
    UINT32 fore_color32, back_color32;
    UINT8 *fptr;
    UINT8 *temp_buf[32 * 32], *ptr8;
    int idx;

    fore_color32 = make_color(fore_color);
    back_color32 = make_color(back_color);

    cmd32 = 0xcc430080;

    if (draw_mode == MODE_TRANSPARENT)
    {
        cmd32 |= 0x00004000; // mono transparency
    }

    outpw(REG_GE2D_CTL, cmd32);

    outpw(REG_GE2D_FGCOLR, fore_color32);
    outpw(REG_GE2D_BGCOLR, back_color32);

    if (font_id == F8x16)
    {
        fptr = (UINT8 *)&FontData16[asc_code][0];
        src_pitch = 32;
        width = 32;
        height = 16;

        ptr8 = (UINT8 *)&temp_buf[0];
        for (idx = 0; idx < 16; idx++)
        {
            *ptr8++ = *fptr++;
            *ptr8++ = 0;
            *ptr8++ = 0;
            *ptr8++ = 0;
        }
        fptr = (UINT8 *)&temp_buf[0];
    }
    else     /* F8x8 */
    {
        fptr = (UINT8 *)&FontData8[asc_code][0];
        src_pitch = 32;
        width = 32;
        height = 8;
        ptr8 = (UINT8 *)&temp_buf[0];
        for (idx = 0; idx < 8; idx++)
        {
            *ptr8++ = *fptr++;
            *ptr8++ = 0;
            *ptr8++ = 0;
            *ptr8++ = 0;
        }
        fptr = (UINT8 *)&temp_buf[0];
    }

    dest_pitch = GFX_WIDTH; // pitch in pixels

    pitch = (dest_pitch << 16) | src_pitch;
    outpw(REG_GE2D_SDPITCH, pitch);

    outpw(REG_GE2D_XYSORG, (int)fptr);
    outpw(REG_GE2D_SRCSPA, 0); // always start from (0,0)

    dest_start = y << 16 | x;
    outpw(REG_GE2D_DSTSPA, dest_start);

    dest_dimension = height << 16 | width;
    outpw(REG_GE2D_RTGLSZ, dest_dimension);

    outpw(REG_GE2D_TRG, 1);

    NU_GE2D_COND_WAIT();

    NU_GE2D_UNLOCK();
}

/**
  * @brief Display font string.
  * @param[in] x x position
  * @param[in] y y position
  * @param[in] str is pointer of display string
  * @param[in] fore_color is color of foreground
  * @param[in] back_color is color of background
  * @param[in] draw_mode is transparent is enable or not
  * @param[in] font_id is selection of 8x8 or 8x16 font
  * @return none
  */
void ge2dFont_PutString(int x, int y, char *str, int fore_color, int back_color, int draw_mode, int font_id)
{
    char *ptr;
    int idx, sx;

    ptr =   str;
    sx = x;
    for (idx = 0; idx < rt_strlen(str); idx++)
    {
        ge2dFont_PutChar(sx, y, *ptr++, fore_color, back_color, draw_mode, font_id);
        sx += 8;    //char width
    }
}

/**
 * Hardware GE2D Initialization
 */
int rt_hw_ge2d_init(void)
{
    g_sNuGe2d.lock = rt_mutex_create("ge2d_lock", RT_IPC_FLAG_PRIO);
    RT_ASSERT(g_sNuGe2d.lock != RT_NULL);

#if defined(DEF_COND_WAIT)
    rt_kprintf("with_cond_wait\n");
    g_sNuGe2d.signal = rt_sem_create("ge2d_wait", 0, RT_IPC_FLAG_FIFO);
    RT_ASSERT(g_sNuGe2d.signal != RT_NULL);

    /* Install ISR & Respond the IRQ */
    rt_hw_interrupt_install(g_sNuGe2d.irqn, nu_ge2d_isr, &g_sNuGe2d, g_sNuGe2d.name);
    rt_hw_interrupt_umask(g_sNuGe2d.irqn);
#endif

    /* Enable GE2D engine clock */
    nu_sys_ipclk_enable(GE2DCKEN);

    return 0;
}

INIT_DEVICE_EXPORT(rt_hw_ge2d_init);
